package com.appspot.mercadobgbr.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.appspot.mercadobgbr.client.ControlBar.Controls;
import com.appspot.mercadobgbr.client.DomUtils.EventRemover;
import com.appspot.mercadobgbr.client.MercadoBGBR.Controller;
import com.appspot.mercadobgbr.shared.Item;
import com.appspot.mercadobgbr.shared.Usuario;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;

/**
 * The main UI for our Application. This is the list of jogos.
 */
public class JogoList extends Page {

	/**
	 * Styles for this Widget. CssResource styles are compiled, minified and
	 * injected into the compiled output for this application. Fewer round trips
	 * since everything is included in the JavaScript :)!
	 */
	public interface Css extends CssResource {
		String checkBoxContainer();

		String checked();

		String plusPartida();

		String plusJogo();

		String jogoRow();

		String itemVenda();

		String ligaSoft();

		String ligaHard();

		String title();

		String unChecked();

		String user();

		String rank();

		String configUsuario();

		String enviado();
	}

	/**
	 * Resources for this Widget.
	 * 
	 */
	public interface Resources extends ControlBar.Resources {
		@Source("resources/checkBox.png")
		ImageResource checkBox();

		@Source("resources/check.png")
		ImageResource checkMark();

		@Source("resources/plusJogo.png")
		ImageResource plusJogo();

		@Source("resources/plusPartida.png")
		ImageResource plusPartida();

		@Source("resources/configUsuario.png")
		ImageResource configUsuario();

		@Source("resources/JogoList.css")
		JogoList.Css jogoListCss();

		@Source("resources/enviado_small.png")
		ImageResource enviado();

	}

	/**
	 * This class wraps JogoData and its associated DOM elements. This class
	 * controls the rendering of Jogo Data to the UI.
	 */
	public class JogoRow extends Widget {
		// private final DivElement checkMark;
		private final Item data;
		private List<EventRemover> removers = new ArrayList<EventRemover>();

		private final DivElement titleElem;
		private final DivElement enviadoElem;

		public JogoRow(Element parentElem, Item item, Element removed) {
			super(parentElem, removed);
			this.data = item;
			Element myElem = getElement();
			JogoList.Css css = resources.jogoListCss();
			myElem.setClassName(css.jogoRow());
			titleElem = Document.get().createDivElement();
			titleElem.setClassName(css.title());

			enviadoElem = Document.get().createDivElement();
			enviadoElem.setClassName(resources.jogoListCss().enviado());
			enviadoElem.setTitle("E-mail já enviado ao vendedor!");

			myElem.appendChild(titleElem);
			myElem.appendChild(enviadoElem);

			renderJogo();

			hookEventListeners();
		}

		public Item getJogoData() {
			return data;
		}

		public void removeFromList() {
			for (int i = 0, n = removers.size(); i < n; i++) {
				removers.get(i).remove();
			}
			removers.clear();

			jogoRowMap.remove(data.getBoardGame().getId());

		}

		public void renderJogo() {
			if (data.getBoardGame() != null) {
				String thumb = data.getBoardGame().getThumb();
				titleElem.getStyle().setProperty("backgroundRepeat", "no-repeat");
				titleElem.getStyle().setProperty("backgroundSize", "100px");
				titleElem.getStyle().setProperty("backgroundImage", "url(\"" + thumb + "\")");
			}
			// checkMark.setClassName(resources.jogoListCss().unChecked());

			NumberFormat z = NumberFormat.getCurrencyFormat("BRL");

			double valorVenda = data.getBoardGame().getValor();
			String textoValor = "Valor à combinar";
			if (valorVenda > 0) {
				textoValor = z.format(valorVenda);
				textoValor = textoValor.replace("R$", "R$ ").replace(".", "*").replace(",", ".")
						.replace("*", ",");
			}
			StringBuilder tituloItem = new StringBuilder();
			tituloItem.append("<b>");
			tituloItem.append(data.getBoardGame().getName());
			tituloItem.append("</b><br>");
			tituloItem.append(textoValor);
			tituloItem.append("<br>");
			tituloItem.append(data.getBoardGame().getVendedor().getNickname());
			titleElem.setInnerHTML(tituloItem.toString());

			if (data.getBoardGame().isEnviado()) {
				enviadoElem.getStyle().setVisibility(Visibility.VISIBLE);
			}
		}

		public void setRowAsNotPersisted() {
			getElement().setClassName(resources.jogoListCss().jogoRow());
		}

		public void setRowAsPersisted(String id) {
			jogoRowMap.remove(data.getBoardGame().getId());
			data.getBoardGame().setId(id);
			jogoRowMap.put(id, JogoRow.this);
		}

		private void hookEventListeners() {
			DomUtils.addEventListener("click", titleElem.getParentElement(), new EventListener() {

				public void onBrowserEvent(Event event) {
					controller.loadJogo(data);
					controller.goToJogoDetails();
				}

			});

		}
	}

	/**
	 * Creates the controls to be added to a JogoList.
	 */
	public static Controls createControls(final Controller controller, JogoList.Resources resources) {
		JogoList.Css css = resources.jogoListCss();

		Controls controls = new Controls(resources);
		controls.addControl(css.plusJogo(), new EventListener() {

			public void onBrowserEvent(Event event) {
				controller.loadJogo(null);
				controller.goToJogoDetails();
			}

		});

		controls.addControl(css.configUsuario(), new EventListener() {

			public void onBrowserEvent(Event event) {
				controller.loadUsuario(usuario);
				controller.goToUsuarioDetails();
			}

		});

		return controls;
	}

	private final Controller controller;
	private boolean isLoggedIn = false;
	private boolean isAdmin = false;
	private boolean isGerente = false;
	private final AnchorElement logoutLink;
	private final DivElement itemVenda;
	private final DivElement ligaSoft;
	private final DivElement ligaHard;
	private final JogoList.Resources resources;
	private final HashMap<String, JogoRow> jogoRowMap = new HashMap<String, JogoRow>();
	private final List<JogoRow> jogosPendingDeleteConfirmation = new ArrayList<JogoRow>();

	private final DivElement userEmail;
	private static Usuario usuario;

	protected JogoList(PageTransitionPanel parent, Controls controls, Controller controller,
			JogoList.Resources resources) {
		super(parent, controls, resources);
		this.controller = controller;
		this.resources = resources;
		Element container = getContentContainer();

		itemVenda = Document.get().createDivElement();
		itemVenda.setClassName(resources.jogoListCss().itemVenda());
		container.appendChild(itemVenda);

		ligaSoft = Document.get().createDivElement();
		ligaSoft.setClassName(resources.jogoListCss().ligaSoft());
		container.appendChild(ligaSoft);

		ligaHard = Document.get().createDivElement();
		ligaHard.setClassName(resources.jogoListCss().ligaHard());
		container.appendChild(ligaHard);

		userEmail = Document.get().createDivElement();
		userEmail.getStyle().setProperty("display", "inline-block");
		userEmail.setInnerText("Carregando...");
		logoutLink = Document.get().createAnchorElement();
		DivElement userInfoContainer = Document.get().createDivElement();
		userInfoContainer.appendChild(userEmail);
		userInfoContainer.appendChild(logoutLink);
		userInfoContainer.setClassName(resources.jogoListCss().user());
		container.appendChild(userInfoContainer);
	}

	public JogoRow addJogoToUi(Item item, Element removed) {
		Element container = getTipoItem(item);

		JogoRow row = new JogoRow(container, item, removed);

		return row;
	}

	private Element getTipoItem(Item item) {
		// if (item.getBoardGame().getAverageWeight() < 2) {
		return itemVenda;
		// } else if (item.getBoardGame().getAverageWeight() < 3) {
		// return ligaSoft;
		// } else
		// return ligaHard;
	}

	public void confirmDeletion() {
		for (int i = 0, n = jogosPendingDeleteConfirmation.size(); i < n; i++) {
			JogoRow row = jogosPendingDeleteConfirmation.get(i);
			row.removeFromList();
		}
		jogosPendingDeleteConfirmation.clear();
	}

	public boolean isLoggedIn() {
		return isLoggedIn;
	}

	public void notifyNotLoggedIn(String loginUrl) {
		getControlBar().disableControls();
		if (loginUrl != null) {
			userEmail.setInnerText("Please ");
			logoutLink.setHref(loginUrl);
			logoutLink.setInnerText(" signin.");
		} else {
			userEmail.setInnerText("Carregando Mercado. Aguarde...");
			// logoutLink.setHref("javascript:location.reload(true);");
			// logoutLink.setInnerText(" Try Refresh");
		}
	}

	public void setUserLoggedIn() {
		isLoggedIn = true;
		isAdmin = usuario.isAdmin();
		isGerente = usuario.isGerente();
		userEmail.setInnerText("Olá, " + usuario.getNickname() + "! (" + usuario.getEmail() + ") ");
		logoutLink.setHref(usuario.getLogoutURL());
		logoutLink.setInnerHTML("<br><br>Sair");

		getControlBar().enableControls();

		getControlBar().disableControls(isGerente);

		if (usuario.isPrimeiroAcesso()) {
			controller.loadUsuario(usuario);
			controller.goToUsuarioDetails();
		}

	}

	/**
	 * Updates the UI to reflect that the underlying jogo has been updated.
	 * 
	 * @param jogo
	 *            the {@link Jogo} that has been updated.
	 * @param oldPriority
	 *            the old priority level of the jogo.
	 * @return returns the updated {@link JogoRow}.
	 */
	public JogoRow updateItem(Item item) {
		String id = item.getBoardGame().getId();
		JogoRow removed = jogoRowMap.remove(id);
		JogoRow row = addJogoToUi(item, removed.getElement());
		if (removed != null) {
			removed.getElement().removeFromParent();
		}
		row.setRowAsPersisted(id);
		return row;
	}

	public void setUsuario(Usuario usuario) {
		JogoList.usuario = usuario;

	}

	public Usuario getUsuario() {
		return usuario;
	}

	public JogoRow removeItem(Item item) {
		JogoRow removed = jogoRowMap.remove(item.getBoardGame().getId());
		if (removed != null) {
			removed.getElement().removeFromParent();
		}
		return removed;
	}

	public void emailEnviado(String idItem) {
		Item item = jogoRowMap.get(idItem).data;
		item.getBoardGame().setEnviado(true);
		updateItem(item);
	}

}
